﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using AfterlifeLib.Projectiles;
using AfterlifeLib.Lighting;

namespace AfterlifeLib.Weapons
{
    public class Gun : Weapon, ICloneable
    {
        /// <summary>
        /// How long the ShootLight should be activated when the gun is fired.
        /// </summary>
        const float SHOOTLIGHT_TIME = 0.02f;

        float ShootLightTimer = 0.0f;

        Light shootLight = new Light("gunFlash", Color.White, 200, 0.7f, Vector3.Zero);
        /// <summary>
        /// A light which the gun activates when fired so a
        /// flash appears.
        /// </summary>
        [ContentSerializerIgnore]
        public Light ShootLight
        {
            get { return shootLight; }
        }

        float reloadTime;
        /// <summary>
        /// Hoeveel tijd het herladen duurd (in seconden)
        /// </summary>
        public float ReloadTime
        {
            get { return reloadTime; }
            set { reloadTime = value; }
        }

        int roundsPerMinute;
        /// <summary>
        /// Het aantal kogels die per minuut kunnen worden afgevuurt
        /// </summary>
        public int RoundsPerMinute
        {
            get { return roundsPerMinute; }
            set { roundsPerMinute = value;  }
        }

        public float TimePerRound
        {
            get { return 60.0f / RoundsPerMinute; }
        }

        int ammoPerClip;
        /// <summary>
        /// Hoeveel ammunitie er in een magazijn past
        /// </summary>
        public int AmmoPerClip
        {
            get { return ammoPerClip; }
            set { ammoPerClip = value; }
        }

        int ammoLeft;
        /// <summary>
        /// Het totale aantal ammunitie die je nog over hebt
        /// in magazijnen
        /// </summary>
        [ContentSerializerIgnore]
        public int AmmoLeft
        {
            get { return ammoLeft; }
            set
            {
                if (value >= 0)
                    ammoLeft = value;
            }
        }

        int clipAmmoLeft;
        /// <summary>
        /// Hoeveel ammunitie er in het huidige magazijn zit
        /// </summary>
        [ContentSerializerIgnore]
        public int ClipAmmoLeft
        {
            get { return clipAmmoLeft; }
        }

        bool isReloading = false;
        /// <summary>
        /// Of we aan het herladen zijn
        /// </summary>
        public bool IsReloading
        {
            get { return isReloading; }
        }

        public Gun()
            : base()
        {
            ShootLight.IsEnabled = false;
        }

        /// <summary>
        /// Maak een nieuw wapen aan.
        /// </summary>
        /// <param name="name">De naam van het wapen.</param>
        /// <param name="description">De descriptie van het wapen.</param>
        /// <param name="ammoPerClip">Hoeveel kogels er in een magazijn passen.</param>
        /// <param name="roundsPerMinute">Hoeveel kogels er per minuut kunnen worden afgevuurd.</param>
        /// <param name="reloadTime">Hoelang het duurd om te herladen (in seconden).</param>
        public Gun(string name, string description, int ammoPerClip, int roundsPerMinute, float reloadTime)
            : base(name, description)
        {
            this.ammoPerClip = ammoPerClip;
            this.roundsPerMinute = roundsPerMinute;
            this.reloadTime = reloadTime;
        }

        public void Update(GameTime gameTime)
        {
            float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;

            ShootLight.Position = new Vector3(Owner.Position.X + Owner.Origin.X, Owner.Position.Y + Owner.Origin.Y, 0);

            //Als we nog moeten wachten om te schieten
            if (TimeUntilNextStrike > 0.0f)
            {
                TimeUntilNextStrike -= delta;
            }

            //Als we aan het herladen waren en de tijd om
            //te herladen is voorbij
            if (isReloading && TimeUntilNextStrike <= 0.0f)
            {
                //Stop met herladen
                isReloading = false;

                //Stop nieuwe kogels in het magazijn
                OnReload();
            }

            if (ShootLight.IsEnabled && ShootLightTimer < SHOOTLIGHT_TIME)
            {
                ShootLightTimer += delta;
            }
            if (ShootLightTimer > SHOOTLIGHT_TIME)
            {
                ShootLight.IsEnabled = false;
            }
        }

        /// <summary>
        /// Gebruik deze methode om te schieten.
        /// </summary>
        /// <param name="pm">De ProjectileManager waar we de kogel aan toevoegen.</param>
        /// <param name="position">Vanaf waar de kogel word afgeschoten.</param>
        /// <param name="angle">In welke hoek de kogel word afgeschoten.</param>
        public void Fire(ProjectileManager pm, Vector2 position, float angle)
        {
            //Als we niet aan het herladen zijn en we lang genoeg
            //hebben gewacht om weer te schieten
            if (TimeUntilNextStrike <= 0.0f && !isReloading)
            {
                //Als we meer dan 0 kogels hebben
                if (ClipAmmoLeft <= 0)
                {
                    //Herlaad
                    Reload();

                    return;
                }

                //Vuur een kogel af
                OnFire(pm, position, angle);
            }
        }

        protected virtual void OnFire(ProjectileManager pm, Vector2 position, float angle)
        {
            ShootLightTimer = 0.0f;
            ShootLight.IsEnabled = true;

            //Stel de tijd in die we moeten wachten om weer te schieten
            TimeUntilNextStrike = TimePerRound;
            //Verwijder een kogel uit het wapen
            clipAmmoLeft -= 1;

            //Voeg de kogel toe
            pm.AddProjectile(position, angle, 800); //TODO: bullet speed
        }

        /// <summary>
        /// Gebruik deze methode om te herladen.
        /// </summary>
        public void Reload()
        {
            //Als we nog niet aan het herladen waren en als we minder kogels
            //in het geweer hebben dan in een magazijn en de kogels die we
            //over hebben meer dan 0 zijn
            if (!isReloading && ClipAmmoLeft < AmmoPerClip && AmmoLeft > 0)
            {
                isReloading = true;

                TimeUntilNextStrike = reloadTime;
            }
        }

        protected virtual void OnReload()
        {
            //Als we het hele magazijn kunnen herladen
            if (AmmoLeft > AmmoPerClip)
            {
                clipAmmoLeft = AmmoPerClip;
                AmmoLeft -= AmmoPerClip;
            }
            //Als we minder dan een heel magazijn kunnen herladen
            else if(AmmoLeft > 0)
            {
                clipAmmoLeft = AmmoLeft;
                AmmoLeft = 0;
            }
        }

        /// <summary>
        /// Initialiseer het wapen.
        /// </summary>
        /// <param name="clipAmmoLeft">De hoeveelheid kogels in het wapen.</param>
        /// <param name="ammoLeft">De hoeveelheid kogels in de magazijnen.</param>
        public void Initialize(int clipAmmoLeft, int ammoLeft)
        {
            this.clipAmmoLeft = clipAmmoLeft;
            this.ammoLeft = ammoLeft;
        }

        public override string ToString()
        {
            return string.Format("Name: {0}, Clip Ammo Left: {1}, Ammo Left: {2}, Reloading: {3}, TUNF: {4}, ShootLight: {5}", 
                Name, 
                ClipAmmoLeft, 
                AmmoLeft, 
                IsReloading, 
                TimeUntilNextStrike,
                ShootLight.IsEnabled);
        }

        public object Clone()
        {
            Gun weapon = new Gun(Name, Description, AmmoPerClip, RoundsPerMinute, ReloadTime);

            return weapon;
        }
    }
}
